/*==============================================================================
**                                  Cuong Chu
**                      Proprietary - Copyright (C) 2014
**------------------------------------------------------------------------------
** Supported MCUs      : MCU STM32
** Supported Compilers : KeilC
**------------------------------------------------------------------------------
** File name         : APP_M3_MAIN.c
**  
** Module name       : Main board
**
** Summary:
**
**= History ===================================================================
** 00.00.01  03/8/2014  Cuong Chu
** - Creation
==============================================================================*/
/******************************************************************************/
/* INCLUSIONS                                                                 */
/******************************************************************************/
#include "lcd/lcd.h"
#include "tim/timer.h"
#include "keypad/keypad.h"
#include "comm/comm.h"
#include "bsp/input.h"
#include "stdio.h"
#include "string.h"
#include "fls/fls.h"
#include "audio/audio.h"
/*******************************************************************************/
/* DEFINITION OF CONSTS                                                        */
/*******************************************************************************/
/* const values */
#define   APP_MAIN_NWKID              0xAABBCCEE
#define   APP_MAIN_PORTA_ID           0xAABBCC0A
#define   APP_MAIN_PORTB_ID           0xAABBCC0B
#define   APP_MAIN_PORTA_PORTNAME     COMM_COM4
#define   APP_MAIN_PORTB_PORTNAME     COMM_COM5
#define   APP_MAIN_MAX_WIRE_NBR       64
#define   APP_MAIN_TIME_LED_OK_ON     500

/* string definition */
#define   APP_DISP_TOTAL              "Total"
#define   APP_DISP_SETTING            "Setting Value"
#define   APP_DISP_TIMEDELAY          "Time Delay"
#define   APP_DISP_WRKSTAT            "Status"
#define   APP_DISP_F1_CAPTION         "SETTING"
#define   APP_DISP_F1_LASTWIRE        "Last Wire"
#define   APP_RP_TITLE                "REPORT"
#define   NULL_VAL                    0x00
#define   DATA_ADDRESS                0x0800A800
/*******************************************************************************/
/* DECLARATION OF LOCAL TYPEDEFS                                               */
/*******************************************************************************/
/* flag start/stop checks cable */
typedef enum
{
  FLG_START_CHECK,
  FLG_STOP_CHECK
}APP_MAIN_FlagType;

/* process checking  */
typedef enum
{
  CHK_STARTING,
  CHK_WAIT_CMD,
  CHK_CHECKING,
  CHK_WAIT_RESP,
  CHK_REPORT,
  CHK_LOW_PORT,
  CHK_ERROR
}APP_MAIN_CableCheckingStateType;

typedef enum
{
  ERR_COM,
  ERR_OVER_WIRE,
}APP_MIAN_CheckingErrorType;
/* client control ID */
typedef enum
{
  SS_MODE_SWITCHING         = 0x11,
  SS_MODE_CABLE_DETECTED    = 0x12,
  SS_MODE_START_CHECK       = 0x13,
  SS_MODE_CHECKING          = 0x14,
  SS_MODE_CABLE_FAILED      = 0x15,
  SS_MODE_CABLE_PASSED      = 0x16,
  SS_MODE_START_DETECT      = 0x17,
  SS_MODE_SET_NBR_WIRES     = 0x18,
  SS_MODE_RESET             = 19
}APP_MAIN_ClientControlSessionType;

/* OK/NG */
typedef enum
{
  OK = 0,
  NG,
  EPT
}APP_MAIN_WorkStatusType;
/* action mode */
typedef enum
{
  MODE_AUTO   = 0x01,
  MODE_MANUAL = 0x02
}APP_MAIN_ActionModeType;
/* report structure */
typedef struct 
{
  APP_MAIN_WorkStatusType   WireStatus;
  uint8_t                   WireIndex;
}APP_MAIN_ReportType; 
/* main structure */
typedef struct
{
  uint16_t                FirstSetup;
  uint32_t                Total;
  uint32_t                SettingValue;
  uint32_t                TimeDelay;
  APP_MAIN_WorkStatusType WorkStatus;
  uint32_t                LastWireNbr;
  APP_MAIN_ActionModeType ActionMode;
  APP_MAIN_ActionModeType LastMode ;
}APP_MAIN_TypeDef;
/*******************************************************************************/
/* DECLARATION OF LOCAL VARIABLES                                              */
/*******************************************************************************/
static const char                  *WorkStatusStr[] = {"OK","NG","  "};
static const char                  *MODE_DISP[]     = {"","AUTO","MANUAL"};
/* main data structure */
static APP_MAIN_TypeDef             CableVerify;
/* form switching keeper */
static uint8_t                      FormIndex = 0;
/* Rx Message */
static ComM_MessageType             RxMsg;
/* Tx Message */
static ComM_MessageType             TxMsg;
/* start/stop checking */
static APP_MAIN_FlagType            StartingCheck = FLG_STOP_CHECK;
/* wire report */
static APP_MAIN_ReportType          WireCheckingReport[APP_MAIN_MAX_WIRE_NBR];
/* start loud for passed */
static uint32_t                     LoudPassedTime = 0;
/* time led ok turn on */
static uint16_t                     TimeLEDOK = 0;
/* time next manual */
static uint32_t                     TimeNextManualHandle = 0;
/* start total count  */
static uint8_t                      StartDelayTotalCount = 0;
/*******************************************************************************/
/* DECLARATION OF LOCAL FUNCTIONS                                              */
/*******************************************************************************/
/*******************************************************************************
** Function name: APP_MAIN_StartLoudPassed ( void  )
** Description  : The function starts loud for passed
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartLoudPassed
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_CheckTotal void  )
** Description  : The function checks total parameter
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_CheckTotal
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_AudioPlay( void  )
** Description  : The function plays audio 
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_AudioPlay
(
  uint32_t TimePlay  ,
  uint8_t  Count     ,
  uint16_t TimeCount 
);
/*******************************************************************************
** Function name: APP_MAIN_ResetReportList( void  )
** Description  : The function resets report list
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_ResetReportList
(
  void 
);
/*******************************************************************************
** Function name: APP_MAIN_FormChecking( void  )
** Description  : The function displays checking status 
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_FormChecking
(
  void 
);
/*******************************************************************************
** Function name: APP_MAIN_Report( void  )
** Description  : The function displays form report
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_Report
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_LEDSignalControl( void  )
** Description  : The function sets LED indicate OK/NG
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_LEDSignalControl
(
  APP_MAIN_WorkStatusType LedIndex 
);
/*******************************************************************************
** Function name: APP_MAIN_WaitingForPulse( void  )
** Description  : The function waits for pulse auto or manual
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_WaitingForPulse
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_ModeSwitching( void  )
** Description  : The function checks mode is switching
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_ModeSwitching
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_CableChecking( void  )
** Description  : The function checks cable
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_CableChecking
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_SavingData( void  )
** Description  : The function stores configuration data to flash memory
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SavingData
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_Setting( void  )
** Description  : The function settings value to parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_Setting
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_FormSwitching( void  )
** Description  : The function is switching form displays on LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_FormSwitching
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_StartupValueSetting( void  )
** Description  : The function starts up all parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartupValueSetting
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_DispMainForm( void  )
** Description  : The function displays main form to LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_DispMainForm
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_UpdateMainForm( void  )
** Description  : The function displays parameters of the main form
** Parameter    : line - line to update
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_UpdateMainForm
(
  uint8_t line
);
/*******************************************************************************
** Function name: APP_MAIN_SubForm1( void  )
** Description  : The function displays sub form into LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SubForm1
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_UpdateSubform1( void  )
** Description  : The function displays update all values of sub form to LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_UpdateSubform1
(
  uint8_t   line,
  uint32_t  value
);

/* set LED OK */
static void APP_MAIN_StartLEDOK
(
  void
)
{
  if(TimeLEDOK)
  {
    APP_MAIN_LEDSignalControl(OK);
    TimeLEDOK--;
    Timer_DelayMs(1);
  }
  else
  {
    APP_MAIN_LEDSignalControl(EPT);
  }
}


static void APP_MAIN_DecrementTimeNextHandle
(
  void
)
{
  if(TimeNextManualHandle)
  {
    TimeNextManualHandle--;
    Timer_DelayMs(1);
  }
  else
  {
  
  }
}
/*******************************************************************************
** Function name: main( void  )
** Description  : The main function
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/

int main(void)
{

  /* key return value */
  KEYP_KeyType      KeyValue = KEY_INVALID;
  /* initialize system tick timer */
  Timer_SystemTickTimerInit();
  ComM_Init(APP_MAIN_NWKID,APP_MAIN_PORTA_PORTNAME);
  ComM_Init(APP_MAIN_NWKID,APP_MAIN_PORTB_PORTNAME);
  /* enabled interrupt request */
  ComM_EnableReceivePort(APP_MAIN_PORTA_PORTNAME);
  ComM_EnableReceivePort(APP_MAIN_PORTB_PORTNAME);
  /* initialize input pin */
  INPUT_IOEnableClock();
  INPUT_InputInit(IN_CH_AUTO);
  INPUT_InputInit(IN_CH_MANUAL);
  /* initialize output led control */
  OUTPUT_IOEnableClock();
  OUTPUT_OutputInit(OUT_LED_OK);
  OUTPUT_OutputInit(OUT_LED_NG);
  OUTPUT_OutputSetLogic(OUT_LED_OK,STD_LOW);
  OUTPUT_OutputSetLogic(OUT_LED_NG,STD_LOW);
	/* initialize LCD 20x4 */
  LCD_StartDisplay();
  /* clear LCD screen */
  LCD_ClearScreen() ;
  /* initialize keypad */
  KEYP_Init();
  /* start up value setting */
  APP_MAIN_StartupValueSetting();
  /* default display on LCD */
  APP_MAIN_DispMainForm();
  /* init audio driver */
  AUDIO_Init();
  /* delay 500ms */
	while(1)
  {
    /* communication thread */
    ComM_MainFunction();
    /* waiting for pulse check */
    APP_MAIN_WaitingForPulse();
    /* check cable thread */
    APP_MAIN_CableChecking();
    /* switching checking mode */
    APP_MAIN_ModeSwitching();
    /* check total */
    APP_MAIN_CheckTotal();
    /* scan keypad */
    KeyValue = KEYP_ScanKey();
    APP_MAIN_DecrementTimeNextHandle();
    /* loud for passed */
    APP_MAIN_StartLoudPassed();
    /* check key is pressed if its occur */
    /* LED signal */
    APP_MAIN_StartLEDOK();
    switch(KeyValue)
    {
      case KEY_HASH:
        /* display sub form */
        APP_MAIN_SubForm1();
        /* enter setting */
        APP_MAIN_Setting();
        /* display back to main form  */
        APP_MAIN_DispMainForm();
      break;
      case KEY_B:
        /* reset total */
        CableVerify.Total = 0;
        APP_MAIN_SavingData();
        APP_MAIN_UpdateMainForm(0);
      default: 
        /* do nothing */
      break;
    }
  }
}
/*******************************************************************************/
/* DEFINITION OF LOCAL FUNCTIONS                                               */
/*******************************************************************************/
/*******************************************************************************
** Function name: APP_MAIN_StartLoudPassed ( void  )
** Description  : The function starts loud for passed
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartLoudPassed
(
  void
)
{
  if(LoudPassedTime)
  {
    APP_MAIN_AudioPlay(1000,1,1);
    LoudPassedTime--;
  }
  else
  {
  
  }
}
/*******************************************************************************
** Function name: APP_MAIN_CheckTotal void  )
** Description  : The function checks total parameter
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_CheckTotal
(
  void 
)
{
  if(CableVerify.Total >= CableVerify.SettingValue && !LoudPassedTime)
  {
    Timer_DelayMs(1200);
    APP_MAIN_AudioPlay(800,1,1000);
    CableVerify.Total = 0;
    APP_MAIN_SavingData();
    APP_MAIN_UpdateMainForm(0);
  }
  else
  {
    /* do nothing */
  }
}

/*******************************************************************************
** Function name: APP_MAIN_ResetReportList( void  )
** Description  : The function resets report list
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_ResetReportList
(
  void 
)
{
  uint8_t LocalCounter = 0;
  for(LocalCounter = 0; LocalCounter < APP_MAIN_MAX_WIRE_NBR; LocalCounter++)
  {
    WireCheckingReport[LocalCounter].WireStatus = EPT;
    WireCheckingReport[LocalCounter].WireIndex  = 0;    
  }
}
/*******************************************************************************
** Function name: APP_MAIN_LEDSignalControl( void  )
** Description  : The function indicates LED OK/NG
** Parameter    : LEDStatus - Select LED OK/NG
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_LEDSignalControl
(
  APP_MAIN_WorkStatusType LEDStatus
)
{
  switch(LEDStatus)
  {
    /* on led OK and off led NG */
    case OK:
      OUTPUT_OutputSetLogic(OUT_LED_OK,STD_HIGH);
      OUTPUT_OutputSetLogic(OUT_LED_NG,STD_LOW);
    break;
    /* on led NG and off led OK */
    case NG:
      OUTPUT_OutputSetLogic(OUT_LED_OK,STD_LOW);
      OUTPUT_OutputSetLogic(OUT_LED_NG,STD_HIGH);
    break;
    /* disable all led */
    case EPT:
      OUTPUT_OutputSetLogic(OUT_LED_OK,STD_LOW);
      OUTPUT_OutputSetLogic(OUT_LED_NG,STD_LOW);
    break;
    default: /* do nothing */;break;
  }
}
/*******************************************************************************
** Function name: APP_MAIN_CableChecking( void  )
** Description  : The function checks cable
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_CableChecking
(
  void
)
{
  uint8_t                             EXIT = 0;
  /* checking state machine */
  APP_MAIN_CableCheckingStateType     CheckingSM = CHK_STARTING;
  uint8_t                             WireIndexToCheck=0;
  uint32_t                            Timeout;
  APP_MIAN_CheckingErrorType          ErrorTracer;
	uint8_t                             i,j;
	uint64_t                            Tmp;
  /* check cable is started */
  if(StartingCheck == FLG_START_CHECK)
  {
    /* clear flag */
    StartingCheck = FLG_STOP_CHECK;
    /* reset report list */
    APP_MAIN_ResetReportList();
    /* display cable checking cover */
    APP_MAIN_FormChecking();
    do
    {
      /* run COMM thread */
      ComM_MainFunction();
      /* state of checking process */
      switch(CheckingSM)
      {
        case CHK_STARTING:
          /* indicate to PORTA to checking cable with specified wires number */
          TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
          TxMsg.DstID = APP_MAIN_PORTA_ID;
          TxMsg.SrcID = APP_MAIN_NWKID;
          TxMsg.MsgID = SS_MODE_START_CHECK;
          TxMsg.Dlc   = 0;
          /* number of wires to check */
          TxMsg.Data[0] = CableVerify.LastWireNbr;
          ComM_AddMessageToQueue(&TxMsg);
          ComM_MainFunction();
          ComM_MainFunction();
          ComM_MainFunction();
          ComM_MainFunction();
          /* write to port B */
          TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
          TxMsg.DstID = APP_MAIN_PORTB_ID;
          ComM_AddMessageToQueue(&TxMsg);
					ComM_MainFunction();
					ComM_MainFunction();
					ComM_MainFunction();
					ComM_MainFunction();				
          /* preparing parameters for checking */
          WireIndexToCheck = 0;
          CheckingSM = CHK_WAIT_CMD;
          Timeout = 50;
        break;
        case CHK_WAIT_CMD:
          if(Timeout)
          {
            Timeout--;
            Timer_DelayMs(1);
          }
          else
          {
            CheckingSM = CHK_LOW_PORT;
          }
        break;
        case CHK_LOW_PORT:
            /* indicate to PORTA to checking cable with specified wires number */
            TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
            TxMsg.DstID = APP_MAIN_PORTA_ID;
            TxMsg.SrcID = APP_MAIN_NWKID;
            TxMsg.MsgID = SS_MODE_CHECKING;
            TxMsg.Dlc   = 1;
            /* wire index to check to port A */
            TxMsg.Data[0] = WireIndexToCheck;
            ComM_AddMessageToQueue(&TxMsg);
						ComM_MainFunction();
						ComM_MainFunction();
						ComM_MainFunction();   
            CheckingSM = CHK_CHECKING;
				    //Timer_DelayMs(100);
        break;
        case CHK_CHECKING:
          if(WireIndexToCheck < (uint8_t)CableVerify.LastWireNbr && WireIndexToCheck < APP_MAIN_MAX_WIRE_NBR)
          {
            /* wire index to check to port B */
            TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
            TxMsg.DstID = APP_MAIN_PORTB_ID;
            TxMsg.SrcID = APP_MAIN_NWKID;
            TxMsg.MsgID = SS_MODE_CHECKING;
            TxMsg.Dlc   = 1;
            TxMsg.Data[0] = WireIndexToCheck;
            ComM_AddMessageToQueue(&TxMsg);	
						ComM_MainFunction();
						ComM_MainFunction();
						ComM_MainFunction();		
            /* set time out */
            Timeout = 100;
            /* wait reponse from client */
            CheckingSM = CHK_WAIT_RESP;            
          }
          else
          {
            /* report */
            CheckingSM = CHK_REPORT;
          }          
        break;
        case CHK_WAIT_RESP:
          if(Timeout)
          {
            Timeout--;
            Timer_DelayMs(1);
            if(ComM_ReadMsgFromQueue(&RxMsg) == COMM_OK)
            {
              /* verify message */
              /* check ID its message come from PORTB */
              /* Message ID is wire passed */
              if(   RxMsg.SrcID == APP_MAIN_PORTB_ID
                 && RxMsg.MsgID == SS_MODE_CABLE_PASSED
                 && RxMsg.Data[0] == WireIndexToCheck
                 )
              {
                WireCheckingReport[WireIndexToCheck].WireIndex = WireIndexToCheck+1;
                WireCheckingReport[WireIndexToCheck].WireStatus = OK;
                /* increment wire index to check */
                WireIndexToCheck++;
                /* next wire to check */
                CheckingSM = CHK_LOW_PORT;
								//Timer_DelayMs(10);
              }
              /* Message ID is wire passed */
              else if(   RxMsg.SrcID == APP_MAIN_PORTB_ID
                      && RxMsg.MsgID == SS_MODE_CABLE_FAILED
                      && RxMsg.Data[0] == WireIndexToCheck
                     )
              {
                WireCheckingReport[WireIndexToCheck].WireIndex = WireIndexToCheck+1;
                WireCheckingReport[WireIndexToCheck].WireStatus = NG;
                /* increment wire index to check */
                WireIndexToCheck++;
                /* next wire to check */
                CheckingSM = CHK_LOW_PORT;
              }
              else
              {
                /* do nothing */
              }
            }
            else
            {
              /* do nothing */
            }
          }
          else
          {
            /* error communication */
            ErrorTracer = ERR_COM;
            CheckingSM = CHK_CHECKING;
          }
        break;
        case CHK_REPORT:
					/* reset port A */
					TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
					TxMsg.DstID = APP_MAIN_PORTA_ID;
					TxMsg.SrcID = APP_MAIN_NWKID;
					TxMsg.MsgID = SS_MODE_RESET;
					TxMsg.Dlc   = 1;
					/* wire index to check to port A */
					TxMsg.Data[0] = 0xBB;
					ComM_AddMessageToQueue(&TxMsg);
					ComM_MainFunction();
					ComM_MainFunction();
					ComM_MainFunction();	
					ComM_MainFunction();
				  ComM_MainFunction();
          /* report */
          APP_MAIN_Report();
        /* indicate to PORTA to checking cable with specified wires number */
          TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
          TxMsg.DstID = APP_MAIN_PORTA_ID;
          TxMsg.SrcID = APP_MAIN_NWKID;
          TxMsg.MsgID = SS_MODE_START_DETECT;
          TxMsg.Dlc   = 1;
          /* number of wires to check */
          TxMsg.Data[0] = (uint8_t)CableVerify.LastWireNbr;
          ComM_AddMessageToQueue(&TxMsg);        
          EXIT = 1;
        break;
        case CHK_ERROR:
          /* display error */
          LCD_ClearScreen();
          LCD_SetCursorPosition(1,7);
          LCD_Printf("ERROR");
          LCD_SetCursorPosition(2,0);
          LCD_Printf("ERR#01: ERR_COM");
          Timer_DelayMs(1000);
          EXIT = 1;
        break;
        default: break;
      }
      
    }
    while(!EXIT);
    /* display main form */
    APP_MAIN_DispMainForm();
  }
  else
  {
    /* do nothing */
  }
}
/*******************************************************************************
** Function name: APP_MAIN_ModeSwitching( void  )
** Description  : The function checks mode is switching
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_ModeSwitching
(
  void
)
{
  /* check auto pin */
  if(INPUT_ReadInput(IN_CH_AUTO) == STD_LOW)
  {
    CableVerify.ActionMode = MODE_AUTO;
    if(CableVerify.LastMode != MODE_AUTO)
    {
      /* indicate to PORTA is in auto mode */
      TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
      TxMsg.DstID = APP_MAIN_PORTA_ID;
      TxMsg.SrcID = APP_MAIN_NWKID;
      TxMsg.MsgID = SS_MODE_SWITCHING;
      TxMsg.Dlc   = 1;
      TxMsg.Data[0] = MODE_AUTO;
      ComM_AddMessageToQueue(&TxMsg);
      /* indicate to port B */
      TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
      TxMsg.DstID = APP_MAIN_PORTB_ID;
      ComM_AddMessageToQueue(&TxMsg);
      CableVerify.LastMode = MODE_AUTO;
      APP_MAIN_SavingData();
    }
    else
    {
      /* do nothing */
    }
  }
  else
  {
    CableVerify.ActionMode = MODE_MANUAL;
    if(CableVerify.LastMode != MODE_MANUAL)
    {
      /* indicate to PORTA is in manual mode */
      TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
      TxMsg.DstID = APP_MAIN_PORTA_ID;
      TxMsg.SrcID = APP_MAIN_NWKID;
      TxMsg.MsgID = SS_MODE_SWITCHING;
      TxMsg.Dlc   = 1;
      TxMsg.Data[0] = MODE_MANUAL;
      ComM_AddMessageToQueue(&TxMsg);
      /* indicate to port B */
      TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
      TxMsg.DstID = APP_MAIN_PORTB_ID;
      ComM_AddMessageToQueue(&TxMsg);
      
      CableVerify.LastMode = MODE_MANUAL;
      APP_MAIN_SavingData();
    }
    else
    {
      /* do nothing */
    }
  }
}
/*******************************************************************************
** Function name: APP_MAIN_WaitingForPulse( void  )
** Description  : The function waits for pulse auto or manual
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_WaitingForPulse
(
  void
)
{
  /* Checking mode is using */
  if(CableVerify.ActionMode == MODE_AUTO)
  {
    if(ComM_ReadMsgFromQueue(&RxMsg) == COMM_OK )
    {
      /* verify message */
      /* check ID its message come from PORTB */
      /* Message ID its is cable detected */
      if(   RxMsg.SrcID == APP_MAIN_PORTB_PORTNAME
         || RxMsg.MsgID == SS_MODE_CABLE_DETECTED)
      {
        /* start check cable */
        StartingCheck = FLG_START_CHECK;
      }
      else
      {
        /* do nothing */
      }
    }
    else
    {
      /* do nothing */
    }
  }
  else
  {
    if(INPUT_ReadInput(IN_CH_MANUAL) == STD_LOW)
    {
      /* wait for input released */
      while(INPUT_ReadInput(IN_CH_MANUAL) == STD_LOW)
      {
        /* do nothing */
      }
      /* start check cable */
      StartingCheck = FLG_START_CHECK;
    }
    else
    {
      /* do nothing */
    }
  }
}
/*******************************************************************************
** Function name: APP_MAIN_SavingData( void )
** Description  : The function store configuration data to flash memory
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SavingData
(
  void
)
{

  uint8_t *pData = (uint8_t*)&CableVerify;
  /* unlock  */
  Fls_Unlock(NULL_VAL,NULL_VAL,(Fls_FunctionCodeType)NULL_VAL);
  Fls_EraseSector(DATA_ADDRESS);
  Fls_ProgramPage(DATA_ADDRESS,sizeof(CableVerify),pData);
  Fls_Lock((Fls_FunctionCodeType)NULL_VAL);
}
/*******************************************************************************
** Function name: APP_MAIN_StartupValueSetting( void  )
** Description  : The function starts up all parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartupValueSetting
(
  void
)
{
  uint8_t *BufferPtr = (uint8_t*)&CableVerify;
  uint16_t ReadSize = sizeof(CableVerify);
  uint32_t Address = DATA_ADDRESS;
  while(ReadSize)
  {
    *(BufferPtr++) = *(uint8_t*)Address;
    /* next address */
    Address++;
    /* decrement counter */
    ReadSize--;
  }
  /* check default setting */
  if(CableVerify.FirstSetup != 0xFAFA)
  {
    /* set default value */
    CableVerify.Total = 0;
    CableVerify.SettingValue = 10;
    CableVerify.TimeDelay = 1;
    CableVerify.WorkStatus = EPT;
    CableVerify.ActionMode = MODE_MANUAL;
    CableVerify.FirstSetup = 0xFAFA;
    CableVerify.LastWireNbr = 10;
    APP_MAIN_SavingData();
  
  }
  else
  {
//     /* check auto pin */
//     if(CableVerify.ActionMode == MODE_AUTO)
//     {
//       /* indicate to PORTA is in auto mode */
//       TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
//       TxMsg.DstID = APP_MAIN_PORTA_ID;
//       TxMsg.SrcID = APP_MAIN_NWKID;
//       TxMsg.MsgID = SS_MODE_SWITCHING;
//       TxMsg.Dlc   = 1;
//       TxMsg.Data[0] = MODE_AUTO;
//       ComM_AddMessageToQueue(&TxMsg);
//       /* indicate to port B */
//       TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
//       TxMsg.DstID = APP_MAIN_PORTB_ID;
//       ComM_AddMessageToQueue(&TxMsg);
//     }
//     else
//     {
//       /* indicate to PORTA is in manual mode */
//       TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
//       TxMsg.DstID = APP_MAIN_PORTA_ID;
//       TxMsg.SrcID = APP_MAIN_NWKID;
//       TxMsg.MsgID = SS_MODE_SWITCHING;
//       TxMsg.Dlc   = 1;
//       TxMsg.Data[0] = MODE_MANUAL;
//       ComM_AddMessageToQueue(&TxMsg);
//       /* indicate to port B */
//       TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
//       TxMsg.DstID = APP_MAIN_PORTB_ID;
//       ComM_AddMessageToQueue(&TxMsg);
//     }
//     TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
//     TxMsg.DstID = APP_MAIN_PORTA_ID;
//     TxMsg.MsgID = SS_MODE_SET_NBR_WIRES;
//     TxMsg.Dlc   = 1;
//     TxMsg.Data[0] = CableVerify.LastWireNbr;
//     ComM_AddMessageToQueue(&TxMsg);
//     /* indicate to port B */
//     TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
//     TxMsg.DstID = APP_MAIN_PORTB_ID;
//     ComM_AddMessageToQueue(&TxMsg);
  }
}
/*******************************************************************************
** Function name: APP_MAIN_DispMainForm( void  )
** Description  : The function displays main form to LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_DispMainForm
(
  void
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[6] = {0};
  /* clear LCD screen */
  LCD_ClearScreen();
  /* display total */  
  /* set display string at line 1 */
  LCD_SetCursorFirst(1);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.Total);
  str  = APP_DISP_TOTAL;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(1,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* display setting */
  /* set display string at line 2 */
  LCD_SetCursorFirst(2);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.SettingValue);
  str  = APP_DISP_SETTING;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(2,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* display TimeDelay */
  /* set display string at line 3 */
  LCD_SetCursorFirst(3);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.TimeDelay);
  str  = APP_DISP_TIMEDELAY;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(3,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* display work status */
  /* set display string at line 4 */
  LCD_SetCursorFirst(4);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.LastWireNbr);
  str  = APP_DISP_F1_LASTWIRE;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(4,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
}
/*******************************************************************************
** Function name: APP_MAIN_UpdateMainForm( void  )
** Description  : The function displays parameters of the main form
** Parameter    : line - line to update
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_UpdateMainForm
(
  uint8_t line
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[6] = {0};
  const uint8_t PosX[] = {1,2,3,4};
  /* line to update */
  /* check line index valid */
  if(line < 4)
  {
    /* clear 5 characters at end of line */
    sprintf((char*)TmpBuffer,"     ");
    LCD_SetCursorPosition(PosX[line],20-strlen((const char *)TmpBuffer));
    str = TmpBuffer;
    LCD_Printf(str);
  }
  else
  {
    /* do nothing */
  }
  switch(line)
  {
    case 0:
      /* display total */  
      /* convert value to string */
      sprintf((char*)TmpBuffer,"%d",CableVerify.Total);
      LCD_SetCursorPosition(1,20-strlen((const char *)TmpBuffer));
      str = TmpBuffer;
      LCD_Printf(str);
    break;
    case 1:
      /* display SettingValue */
      /* convert value to string */
      sprintf((char*)TmpBuffer,"%d",CableVerify.SettingValue);
      LCD_SetCursorPosition(2,20-strlen((const char *)TmpBuffer));
      str = TmpBuffer;
      LCD_Printf(str);
    break;
    case 2:
      /* display TimeDelay */
      /* convert value to string */
      sprintf((char*)TmpBuffer,"%d",CableVerify.TimeDelay);
      LCD_SetCursorPosition(3,20-strlen((const char *)TmpBuffer));
      str = TmpBuffer;
      LCD_Printf(str);
    break;
    case 3:
      /* display LastWireNbr */
      /* convert value to string */
      sprintf((char*)TmpBuffer,"%d",CableVerify.LastWireNbr);
      LCD_SetCursorPosition(4,20-strlen((const char *)TmpBuffer));
      str = TmpBuffer;
      LCD_Printf(str);
    break;
    default: break;
  }
}
/*******************************************************************************
** Function name: APP_MAIN_SubForm1( void  )
** Description  : The function displays sub form into LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SubForm1
(
  void
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[6] = {0};
  /* clear LCD screen */
  LCD_ClearScreen();
  /* display title */  
  LCD_SetCursorPosition(1,7);
  str = APP_DISP_F1_CAPTION;
  LCD_Printf(str);
  /* display setting */
  /* set display string at line 2 */
  LCD_SetCursorFirst(2);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.SettingValue);
  str  = APP_DISP_SETTING;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(2,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* display TimeDelay */
  /* set display string at line 3 */
  LCD_SetCursorFirst(3);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",CableVerify.TimeDelay);
  str  = APP_DISP_TIMEDELAY;
  LCD_Printf((uint8_t*)str);
  LCD_SetCursorPosition(3,20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* display last wire value */
  /* set display string at line 4 */
  LCD_SetCursorFirst(4);
  /* convert value to string */
  str  = APP_DISP_F1_LASTWIRE;
  LCD_Printf((uint8_t*)str);
  sprintf((char*)TmpBuffer,"%d",CableVerify.LastWireNbr);
  str = TmpBuffer;
  LCD_SetCursorPosition(4,20-strlen((const char *)TmpBuffer));
  LCD_Printf(str); 
}
/*******************************************************************************
** Function name: APP_MAIN_UpdateSubform1( void  )
** Description  : The function displays update all values of sub form to LCD
** Parameter    : line  -  line to set value
**                value - value to display
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_UpdateSubform1
(
  uint8_t   line,
  uint32_t  value
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[6] = {0};
  const uint8_t PosX[] = {2,3,4};
  /* line 
    0 : display setting value 
    1 : display TimeDelay
    2 : display last wire value  
  */
  /* clear 5 characters at end of line */
  sprintf((char*)TmpBuffer,"     ");
  LCD_SetCursorPosition(PosX[line],20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* convert value to string */
  sprintf((char*)TmpBuffer,"%d",value);
  LCD_SetCursorPosition(PosX[line],20-strlen((const char *)TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
}
/*******************************************************************************
** Function name: APP_MAIN_FormSwitching( void  )
** Description  : The function is switching form displays on LCD
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_FormSwitching
(
  void
)
{
  switch(FormIndex)
  {
     /* main form */
    case 0:
      APP_MAIN_SubForm1();
    break;
    /* sub form 1  */
    case 1:
      APP_MAIN_DispMainForm();
    break;
    default: break;
  }
  /* increment form index */
  if(FormIndex < 2)
  {
    FormIndex++;
  }
  else
  {
    FormIndex = 0;
  }
}
/*******************************************************************************
** Function name: APP_MAIN_Setting( void  )
** Description  : The function settings value to parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_Setting
(
  void
)
{
  /* key return value */
  KEYP_KeyType                 KeyValue = KEY_INVALID;
  uint8_t                      SettingIndex = 0;
  uint8_t                      EXIT = 0;
  uint32_t                     TmpValue ;
  uint8_t                      RoundIndex[3] = {0};
  uint8_t                      RealKeyNbr = 0;
  uint32_t                     *ParamPtr[3] = {&CableVerify.SettingValue,&CableVerify.TimeDelay,&CableVerify.LastWireNbr};
  const uint8_t                PosX[3] = {2,3,4};
  
  /* set cursor at end of line */
  LCD_SetCursorPosition(2,19);
  /* enable cursor blink */
  LCD_EnableCursor();
  /* wait for first key is released */
  while(KEYP_ScanKey() == KEY_HASH){;}
  /* get roundindex */
  for( ; SettingIndex < 3; SettingIndex++)
  {
    TmpValue = *ParamPtr[SettingIndex];
    while(TmpValue / 10)
    {
      TmpValue /= 10;
      RoundIndex[SettingIndex]++;
    }
  }
  /* reset setting index */
  SettingIndex = 0;
  TmpValue = *ParamPtr[0];
  do
  {
    /* read key value */
    KeyValue = KEYP_ScanKey();
    if(KeyValue == KEY_D)
    {
      Timer_DelayMs(100);
      /* waiting for key release */
      while(KEYP_ScanKey() == KEY_D){;}
      {
        Timer_DelayMs(10);
      }
      /* index the bounce */
      if(SettingIndex < 2)
      {
        SettingIndex++;
      }
      else
      {
        SettingIndex = 0;
      }
      LCD_SetCursorPosition(PosX[SettingIndex],19); 
      TmpValue = *ParamPtr[SettingIndex];
    }
    /* exit  */
    else if(KeyValue == KEY_HASH)
    {
      Timer_DelayMs(200);
      EXIT = 1;
    }
    /* clear back one unit */
    else if (KeyValue == KEY_C)
    {
      Timer_DelayMs(200);
      if(TmpValue)
      {
        TmpValue = TmpValue/10;
        /* update display on sub form 1*/
        *ParamPtr[SettingIndex] = TmpValue;
        APP_MAIN_UpdateSubform1(SettingIndex,TmpValue);
        LCD_SetCursorPosition(PosX[SettingIndex],19); 
        /* decrement round index */
        if(RoundIndex[SettingIndex])
        {
          RoundIndex[SettingIndex]--;
        }
        else
        {
          /* do nothing */
        }
      }
      else
      {
        /* do noting */
      }
    }
    else if (KeyValue == KEY_INVALID)
    {
      /* do nothing */
    }
    else if(KeyValue == KEY_A || KeyValue == KEY_ATK ||KeyValue == KEY_HASH ||KeyValue == KEY_B)
    {
      /* do nothing */
    }
    else if(KeyValue == KEY_0 && RoundIndex == 0)
    {
      /* do nothing */
    }
    else
    {
      Timer_DelayMs(100);
      /* waiting for key release */
      while(KEYP_ScanKey() != KEY_INVALID){;}
      /* check setting index */
      switch(KeyValue)
      {
        case KEY_0:RealKeyNbr = 0;break;
        case KEY_1:RealKeyNbr = 1;break;
        case KEY_2:RealKeyNbr = 2;break;
        case KEY_3:RealKeyNbr = 3;break;
        case KEY_4:RealKeyNbr = 4;break;
        case KEY_5:RealKeyNbr = 5;break;
        case KEY_6:RealKeyNbr = 6;break;
        case KEY_7:RealKeyNbr = 7;break;
        case KEY_8:RealKeyNbr = 8;break;
        case KEY_9:RealKeyNbr = 9;break;                 
        default: break;
      }
      if(RoundIndex[SettingIndex] <5)
      {
        /* calculate for number */
        TmpValue *= 10;
        TmpValue += RealKeyNbr;
        RoundIndex[SettingIndex]++;
      }
      else
      {
        /* do nothing */
      } 
      /* update display on sub form 1*/
      *ParamPtr[SettingIndex] = TmpValue;
      APP_MAIN_UpdateSubform1(SettingIndex,TmpValue);
      LCD_SetCursorPosition(PosX[SettingIndex],19); 
    }
    
  }
  while(!EXIT);
  APP_MAIN_SavingData();
  /* disable cursor */
  LCD_DisableCursor();
  /* saving data */
  APP_MAIN_SavingData();
}
/*******************************************************************************
** Function name: APP_MAIN_FormChecking( void  )
** Description  : The function displays checking status 
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_FormChecking
(
  void 
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[20]  = {0};
  uint8_t       LastWireDetect = 0xff;
  /* display title */
  LCD_ClearScreen();
  LCD_SetCursorPosition(1,6);
  LCD_Printf("CHECKING");
  /* display cable length */
  sprintf((char*)TmpBuffer,"CABLE LENGTH: %d",CableVerify.LastWireNbr);
  LCD_SetCursorPosition(2,0);
  str = TmpBuffer;
  LCD_Printf(str);
  /* display mode */
  LCD_SetCursorPosition(3,0);
  str = "MODE: ";
  LCD_Printf(str);
  sprintf((char*)TmpBuffer,"%s",MODE_DISP[CableVerify.ActionMode]);
  LCD_SetCursorPosition(3,20 - strlen (TmpBuffer));
  str = TmpBuffer;
  LCD_Printf(str);
  /* waiting for all wires are entered */
  if(CableVerify.ActionMode == MODE_AUTO)
  {
    /* display wires entered */
    str = "WIRES ENTERED: ";
    LCD_SetCursorPosition(4,0);
    LCD_Printf(str);
    sprintf((char*)TmpBuffer,"%d",0);
    str = TmpBuffer;
    LCD_SetCursorPosition(4,20 - strlen (TmpBuffer));
    LCD_Printf(str);
  /* indicate to PORTA to checking cable with specified wires number */
    TxMsg.Port  = APP_MAIN_PORTA_PORTNAME;
    TxMsg.DstID = APP_MAIN_PORTA_ID;
    TxMsg.SrcID = APP_MAIN_NWKID;
    TxMsg.MsgID = SS_MODE_START_DETECT;
    TxMsg.Dlc   = 1;
    /* number of wires to check */
    TxMsg.Data[0] = (uint8_t)CableVerify.LastWireNbr;
    ComM_AddMessageToQueue(&TxMsg);
    /* write to port B */
    TxMsg.Port  = APP_MAIN_PORTB_PORTNAME;
    TxMsg.DstID = APP_MAIN_PORTB_ID;
    ComM_AddMessageToQueue(&TxMsg);    
    do
    {
      ComM_MainFunction();
      /* check incoming message */
      if(COMM_OK == ComM_ReadMsgFromQueue(&RxMsg))
      {
        /* check valid message */
        if(  RxMsg.SrcID == APP_MAIN_PORTB_ID 
          && RxMsg.MsgID == SS_MODE_START_DETECT)
        {
          if(LastWireDetect != RxMsg.Data[0])
          {
            /* update new value */
            LastWireDetect = RxMsg.Data[0];
            /* display to LCD */
            str = "  ";
            LCD_SetCursorPosition(4,18);
            LCD_Printf(str);
            sprintf((char*)TmpBuffer,"%d",LastWireDetect);
            str = TmpBuffer;
            LCD_SetCursorPosition(4,20 - strlen (TmpBuffer));
            LCD_Printf(str);
          }
          else
          {
            /* do nothing */
          }
        }
        else
        {
          /* do nothing */
        }
      }
      else
      {
        /* do nothing */
      }
    }
    while(LastWireDetect < CableVerify.LastWireNbr || LastWireDetect == 0xff );
  }
  else
  {
    /* do nothing */
  }
}
/*******************************************************************************
** Function name: APP_MAIN_AudioPlay( void  )
** Description  : The function plays audio 
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_AudioPlay
(
  uint32_t TimePlay  ,
  uint8_t  Count     ,
  uint16_t TimeCount 
)
{
  const uint16_t Vector[] = {2048, 2249, 2447, 2642, 2831, 3013, 3185, 3347, 3495, 3630, 3750, 3853, 3939, 4007, 4056, 4085, 4095, 4085, 4056, 4007, 3939, 3853, 3750, 3630, 3495, 3347, 3185, 3013, 2831, 2642, 2447, 2249, 2048, 1847, 1649, 1454, 1265, 1083, 911, 749, 601, 466, 346, 243, 157, 89, 40, 11, 1, 11, 40, 89, 157, 243, 346, 466, 601, 749, 911, 1083, 1265, 1454, 1649, 1847 };
  uint16_t i,j = 0;
  for( ; Count ; Count--)
  {
    for(j = 0; j <TimePlay;j++)
    {
      for(i = 0; i < 64;i++)
      {
        AUDIO_Out(Vector[i],Vector[i]);
        Timer_DelayUs(1);
      }
    }
    Timer_DelayMs(TimeCount);
  }
} 
/*******************************************************************************
** Function name: APP_MAIN_Report( void  )
** Description  : The function displays form report
** Parameter    : None
** Return value : None
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_Report
(
  void
)
{
  uint8_t       *str;
  uint8_t       TmpBuffer[20] = {0};
  uint8_t       WiresPassed = 0;
  uint8_t       WiresFailed = 0;
  uint8_t       LocalCounter = 0;
  uint8_t       WiresIndex = 0;
  KEYP_KeyType  KeyValue = KEY_INVALID;
  uint8_t       EXIT = 0;
  /* get wires passed and failed */
  for(; LocalCounter < CableVerify.LastWireNbr; LocalCounter++)
  {
    if(WireCheckingReport[LocalCounter].WireStatus == OK)
    {
      WiresPassed++;
    }
    else if(WireCheckingReport[LocalCounter].WireStatus == NG)
    {
      WiresFailed++;
    }
  }
  /* cable is not failed */
  if(WiresFailed == 0)
  {
    /* clear LCD screen */
    LCD_ClearScreen();
    /* display title */  
    str  = APP_RP_TITLE;
    LCD_SetCursorPosition(1,7);
    LCD_Printf((uint8_t*)str);
    /* display cable length */
    sprintf((char*)TmpBuffer,"CABLE LENGTH: %d",CableVerify.LastWireNbr);
    LCD_SetCursorPosition(2,0);
    str = TmpBuffer;
    LCD_Printf(str);
    /* status */
    LCD_SetCursorPosition(3,0);
    LCD_Printf("STATUS: PASS");
    /* on LED */
    APP_MAIN_LEDSignalControl(OK);
    TimeLEDOK = APP_MAIN_TIME_LED_OK_ON;
    LoudPassedTime = 1;
    Timer_DelayMs(350);

    StartDelayTotalCount = 1;
    /* increment total */
    if(CableVerify.Total < CableVerify.SettingValue && !TimeNextManualHandle)
    {
      CableVerify.Total ++;
      APP_MAIN_SavingData();
      APP_MAIN_UpdateMainForm(0);
      TimeNextManualHandle = CableVerify.TimeDelay*1000;
    }
    else
    {
      /* do nothing */
    }    
  }
  else
  {
    /* clear LCD screen */
    LCD_ClearScreen();
    /* display title */  
    str  = APP_RP_TITLE;
    LCD_SetCursorPosition(1,7);
    LCD_Printf((uint8_t*)str);
    /* display summary test result */
    LCD_SetCursorFirst(2);
    /* convert value to string */
    sprintf((char*)TmpBuffer,"PASS: %d FAILED: %d",WiresPassed,WiresFailed);
    str = TmpBuffer;
    LCD_Printf(str);
    /* display wires selection */
    /* get first wire error */
    while(WireCheckingReport[WiresIndex].WireStatus != NG && WiresIndex < CableVerify.LastWireNbr-1)
    {
      /* limit */
      if(WiresIndex < CableVerify.LastWireNbr-1)
      {
        WiresIndex++;
      }
      else
      {
        WiresIndex = 0;
      }
    }
    /* set display string at line 3 */
    LCD_SetCursorFirst(3);
    str = "<";
    LCD_Printf(str);
    /* convert value to string */
    sprintf((char*)TmpBuffer,"Wire %d",WiresIndex+1);
    LCD_SetCursorPosition(3,6);
    str = TmpBuffer;
    LCD_Printf(str);
    LCD_SetCursorPosition(3,19);
    str = ">";
    LCD_Printf(str);
    /* display work status */
    /* set display string at line 4 */
    LCD_SetCursorFirst(4);
    /* convert value to string */
    str  = APP_DISP_WRKSTAT;
    LCD_Printf((uint8_t*)str);
    LCD_SetCursorPosition(4,20-strlen(WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus]));
    str = (uint8_t *)WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus];
    LCD_Printf(str);
    APP_MAIN_LEDSignalControl(NG);
    /* loud indicates cable is passed */
    APP_MAIN_AudioPlay(300,5,300);
    /* list view */
    do
    {
      /* scanning keypad */
      KeyValue = KEYP_ScanKey();
      if(KeyValue != KEY_INVALID)
      {
        Timer_DelayMs(200);      
        /* check key pressed */
        switch(KeyValue)
        {
          case KEY_C:
            WiresIndex++;
            while(WireCheckingReport[WiresIndex].WireStatus != NG)
            {
              /* limit display */
              if(WiresIndex < CableVerify.LastWireNbr-1)
              {
                WiresIndex++;
              }
              else
              {
                WiresIndex = 0;
              }
            }
            /* display wire index */
            sprintf((char*)TmpBuffer,"%d ",WiresIndex+1);
            LCD_SetCursorPosition(3,11);
            str = TmpBuffer;
            LCD_Printf(str);
            /* display wire status */
            LCD_SetCursorPosition(4,20-strlen(WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus]));
            str = (uint8_t*)WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus];
            LCD_Printf(str);
          break;
          case KEY_D:
             WiresIndex--;
            while(WireCheckingReport[WiresIndex].WireStatus != NG)
            {
              /* limit display */
              if(WiresIndex)
              {
                WiresIndex--;
              }
              else
              {
                WiresIndex = CableVerify.LastWireNbr - 1;
              }
            }
            /* display wire index */
            sprintf((char*)TmpBuffer,"%d ",WiresIndex+1);
            LCD_SetCursorPosition(3,11);
            str = TmpBuffer;
            LCD_Printf(str);
            /* display wire status */
            LCD_SetCursorPosition(4,20-strlen(WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus]));
            str = (uint8_t*)WorkStatusStr[WireCheckingReport[WiresIndex].WireStatus];
            LCD_Printf(str);
          break;
          case KEY_A:
            /* exit */
            EXIT = 1;
          break;
          default: /* do nothing */break;
        }    
      }
      else
      {
        /* do nothing */
      }
    }while(!EXIT);  
    /* disable LED  */
    APP_MAIN_LEDSignalControl(EPT);
  }

}

